#include <fcntl.h>
#include <unistd.h>
#include <sched.h>
#include <time.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <stdbool.h>
#include "dpu.h"
#include "impp.h"

/*
   示例说明:

   1. 从输入参数解析文件读入两张图片.
   2. 设置输入图片的尺寸信息，
   3. 设置DPU 为写回模式.
   4. 循环改变DPU输入信息，观察屏幕现象.

   重点:
   使用的地址为 vaddr = malloc 的地址而不是物理地址.
   */

#define FILE1_SIZE (720 * 1280 * 4)     // BGRA8888
#define FILE2_SIZE (640 * 480 * 3 / 2)  // NV12

void print_usage(const char *prog_name) {
	fprintf(stderr,
			"Usage: %s <input1.bgra> <input2.nv12> [-o output] [-h]\n"
			"\n"
			"Requirements:\n"
			"  input1.bgra   - Must be 720x1280 BGRA8888 format (%d bytes)\n"
			"  input2.nv12   - Must be 640x480 NV12 format (%d bytes)\n"
			"\n"
			"Options:\n"
			"  -o <output>   - Specify output file path\n"
			"  -h            - Show this help message\n"
			"\n"
			"Example:\n"
			"  %s image1.bgra image2.nv12\n",
			"  %s image1.bgra image2.nv12 -o result.rgba\n",
			prog_name, FILE1_SIZE, FILE2_SIZE, prog_name);
}

int validate_file(const char *filename, size_t expected_size) {
	struct stat st;
	if (stat(filename, &st) == -1) {
		perror("stat failed");
		return -1;
	}
	if (st.st_size != expected_size) {
		fprintf(stderr, "Error: %s has invalid size (%ld bytes), expected %ld bytes\n",
				filename, st.st_size, expected_size);
		return -1;
	}
	return 0;
}

int main(int argc, char **argv)
{
	// 解析命令行参数
	int opt;
	char *output_file = NULL;
	int help_flag = 0;
	// 参数解析
	while ((opt = getopt(argc, argv, "o:h")) != -1) {
		switch (opt) {
			case 'o':
				output_file = optarg;
				break;
			case 'h':
				help_flag = 1;
				break;
			default:
				print_usage(argv[0]);
				return -1;
		}
	}

	// 处理-h参数
	if (help_flag) {
		print_usage(argv[0]);
		return 0;
	}

	// 校验输入文件参数
	if (optind + 2 > argc) {
		fprintf(stderr, "Error: Two input files required\n");
		print_usage(argv[0]);
		return -1;
	}

	char *input1 = argv[optind];
	char *input2 = argv[optind + 1];

	// 验证文件格式
	if (validate_file(input1, FILE1_SIZE) != 0 ||
			validate_file(input2, FILE2_SIZE) != 0) {
		print_usage(argv[0]);
		return -1;
	}

	// 初始化 DPU
	IHal_Dpu_InitStruct_t initStruct;
	initStruct.num_outmem = 4;
	IHal_Dpu_Handle_t *dpuHandle = IHal_Dpu_Init(&initStruct);

	// 打开输入文件
	int file1 = open(input1, O_RDWR);
	int file2 = open(input2, O_RDWR);
	if (-1 == file1 || -1 == file2) {
		printf("Open input files failed!\n");
		return -1;
	}

	// 打开输出文件（如果指定）
	int output_fd = -1;
	if (output_file != NULL) {
		output_fd = open(output_file, O_RDWR | O_CREAT | O_TRUNC, 0666);
		if (-1 == output_fd) {
			printf("Open output file failed!\n");
			close(file1);
			close(file2);
			return -1;
		}
	}

	// 初始化缓冲区
	IMPP_BufferInfo_t layer0buf, layer1buf, displaybuf;
	IHal_Dpu_RDMA_GetFrame(dpuHandle, &displaybuf);
	displaybuf.fd = 0;
	IHal_Dpu_Composer_Set_WbackBuffers(dpuHandle, &displaybuf, 0);

	// 读取输入文件到内存
	layer0buf.vaddr = malloc(FILE1_SIZE);
	read(file1, layer0buf.vaddr, FILE1_SIZE);
	lseek(file1, 0, SEEK_SET);
	read(file1, displaybuf.vaddr, FILE1_SIZE);
	IHal_Dpu_RDMA_PutFrame(dpuHandle, &displaybuf);

	layer1buf.vaddr = malloc(FILE2_SIZE);
	read(file2, layer1buf.vaddr, FILE2_SIZE);

	// 配置 DPU 参数
	IHal_Dpu_FrameDesc_t frame;
	memset(&frame, 0, sizeof(IHal_Dpu_FrameDesc_t));
	frame.dpu_func = DPU_OSD_Func;
	frame.func_desc.osd_frame.osd_flags = Dpu_Layer0 | Dpu_Layer1;
	frame.func_desc.osd_frame.outWidth = 720;
	frame.func_desc.osd_frame.outHeight = 1280;
	frame.func_desc.osd_frame.wback_enable = 1;
	frame.func_desc.osd_frame.wback_fmt = IMPP_PIX_FMT_BGRA_8888;
	frame.func_desc.osd_frame.layer[0].srcFmt = IMPP_PIX_FMT_BGRA_8888;
	frame.func_desc.osd_frame.layer[0].srcWidth = 720;
	frame.func_desc.osd_frame.layer[0].srcHeight = 1280;
	frame.func_desc.osd_frame.layer[0].scale_enable = 1;
	frame.func_desc.osd_frame.layer[0].scaleWidth = 720;
	frame.func_desc.osd_frame.layer[0].scaleHeight = 1280;
	frame.func_desc.osd_frame.layer[0].srcCropx = 200;
	frame.func_desc.osd_frame.layer[0].srcCropy = 600;
	frame.func_desc.osd_frame.layer[0].srcCropw = 500;
	frame.func_desc.osd_frame.layer[0].srcCroph = 500;
	frame.func_desc.osd_frame.layer[0].osd_posX = 0;
	frame.func_desc.osd_frame.layer[0].osd_posY = 0;
	frame.func_desc.osd_frame.layer[0].osd_order = DPU_OSD_Order1;
	frame.func_desc.osd_frame.layer[0].alpha = 255;
	frame.func_desc.osd_frame.layer[0].paddr = 0; //layer0buf.paddr;
	frame.func_desc.osd_frame.layer[0].color_order = DPU_CFG_COLOR_RGB;
	frame.func_desc.osd_frame.layer[0].vaddr = layer0buf.vaddr;     /*!< 使用TLB. */

	frame.func_desc.osd_frame.layer[1].srcFmt = IMPP_PIX_FMT_NV12;
	frame.func_desc.osd_frame.layer[1].srcWidth = 640;
	frame.func_desc.osd_frame.layer[1].srcHeight = 480;
	frame.func_desc.osd_frame.layer[1].srcCropx = 0;
	frame.func_desc.osd_frame.layer[1].srcCropy = 0;
	frame.func_desc.osd_frame.layer[1].srcCropw = 0;
	frame.func_desc.osd_frame.layer[1].srcCroph = 0;
	frame.func_desc.osd_frame.layer[1].scale_enable = 1;
	frame.func_desc.osd_frame.layer[1].scaleWidth = 320;
	frame.func_desc.osd_frame.layer[1].scaleHeight = 240;
	frame.func_desc.osd_frame.layer[1].osd_posX = 100;
	frame.func_desc.osd_frame.layer[1].osd_posY = 200;
	frame.func_desc.osd_frame.layer[1].osd_order = DPU_OSD_Order3;
	frame.func_desc.osd_frame.layer[1].alpha = 200;
	frame.func_desc.osd_frame.layer[1].paddr = 0; //layer1buf.paddr;
	frame.func_desc.osd_frame.layer[1].color_order = DPU_CFG_COLOR_RGB;
	frame.func_desc.osd_frame.layer[1].vaddr = layer1buf.vaddr;
	frame.func_desc.osd_frame.layer[1].uv_vaddr = (layer1buf.vaddr + 640 * 480);

	// 主循环处理
	int i = 0;
	int count = 3000;
	unsigned int src_w = frame.func_desc.osd_frame.layer[0].srcWidth;
	unsigned int src_h = frame.func_desc.osd_frame.layer[0].srcHeight;
	IMPP_FrameInfo_t outframe;

	while (count--) {
		unsigned int cropx = 100 + i;
		unsigned int cropy = 100 + i;
		unsigned int cropw = 100 + i;
		unsigned int croph = 100 + i;

		cropx %= src_w;
		cropy %= src_h;
		cropw %= src_w;
		croph %= src_h;

		/*iterate crop size of layer 0*/
		frame.func_desc.osd_frame.layer[0].srcCropx = cropx;
		frame.func_desc.osd_frame.layer[0].srcCropy = cropy;
		frame.func_desc.osd_frame.layer[0].srcCropw = cropw;
		frame.func_desc.osd_frame.layer[0].srcCroph = croph;

		printf("src crop[%d, %d, %d, %d]\n", cropx, cropy, cropw, croph);
		frame.func_desc.osd_frame.layer[1].osd_posX = i % 720;
		frame.func_desc.osd_frame.layer[1].osd_posY = i % 1280;

		// 启动 DPU 处理
		IHal_Dpu_Composer_Process(dpuHandle, &frame);

		// 获取并写入输出数据（如果启用）
		IHal_Dpu_Composer_GetFrame(dpuHandle, &outframe);

		IHal_Dpu_Composer_ReleaseFrame(dpuHandle, &outframe);

		i++;
	}

	if (output_fd != -1) {
		lseek(output_fd, 0, SEEK_SET);
		write(output_fd, outframe.vaddr, outframe.size);
	}

	// 清理资源
	IHal_Dpu_Deinit(dpuHandle);
	close(file1);
	close(file2);
	if (output_fd != -1)
		close(output_fd);

	return 0;
}
